package com.ax.framework.jfinal.aop


import com.ax.getTypeOfArray
import kotlin.reflect.KParameter
import java.lang.reflect.Constructor
import java.lang.reflect.Method
import kotlin.reflect.jvm.kotlinFunction

object KotlinDetector {

    //
    fun getParameterNames(method: Method): Array<String?>? {
        if (!isKotlinType(method.declaringClass)) {
            return null
        }

        try {
            val function = method.kotlinFunction
            return if (function != null) getParameterNames(function.parameters) else null
        } catch (ex: UnsupportedOperationException) {
            return null
        }

    }

    fun getParameterNames(ctor: Constructor<*>): Array<String?>? {
        if (ctor.declaringClass.isEnum || !isKotlinType(ctor.declaringClass)) {
            return null
        }

        try {
            val function = ctor.kotlinFunction
            return if (function != null) getParameterNames(function.parameters) else null
        } catch (ex: UnsupportedOperationException) {
            return null
        }

    }

    private fun getParameterNames(parameters: List<KParameter>): Array<String?> {
        val filteredParameters = parameters
                // Extension receivers of extension methods must be included as they appear as normal method parameters in Java
                .filter { p -> KParameter.Kind.VALUE == p.kind || KParameter.Kind.EXTENSION_RECEIVER == p.kind }
        val parameterNames = arrayOfNulls<String?>(filteredParameters.size)
        for (i in filteredParameters.indices) {
            val parameter = filteredParameters[i]
            // extension receivers are not explicitly named, but require a name for Java interoperability
            // $receiver is not a valid Kotlin identifier, but valid in Java, so it can be used here
            val name = if (KParameter.Kind.EXTENSION_RECEIVER == parameter.kind) "\$receiver" else parameter.name
            parameterNames[i] = name
        }
        return parameterNames
    }


    private val kotlinMetadata: Class<Annotation>?

    private val kotlinReflectPresent = true

    init {
        var metadata: Class<*>?
        val classLoader = KotlinDetector::class.java.classLoader
        try {
            metadata = Class.forName("kotlin.Metadata")
        } catch (ex: ClassNotFoundException) {
            // Kotlin API not available - no Kotlin support
            metadata = null
        }

        kotlinMetadata = metadata as Class<Annotation>
    }

    /**
     * Determine whether the given `Class` is a Kotlin type
     * (with Kotlin metadata present on it).
     */
    fun isKotlinType(clazz: Class<*>): Boolean {

        return kotlinMetadata != null && clazz.getDeclaredAnnotation<Annotation>(kotlinMetadata) != null
    }

}

fun main(args: Array<String>) {
    val list = arrayListOf<String>()
    val typeOfArray = list.toTypedArray().getTypeOfArray()
    println(typeOfArray)

    val b = B<Int, String>()
    b::class.typeParameters.forEach {
        println(it.name)
        println("${it.name}  ${it.variance.name}")
    }

    Class.forName("").kotlin
}

class B<T, R> {

}